#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <pthread.h>
#include <queue>

namespace thread_pool
{
    template <class T>
    class Thread_Pool
    {
    private:
        int _num;
        std::queue<T> _taskqueue;

        pthread_mutex_t _mtx;
        pthread_cond_t _con;

    public:
        void lock()
        {
            pthread_mutex_lock(&_mtx);
        }

        void unlock()
        {
            pthread_mutex_unlock(&_mtx);
        }

        void wait()
        {
            pthread_cond_wait(&_con,&_mtx);
        }

        void wakeup()
        {
            pthread_cond_signal(&_con);
        }

        bool empty()
        {
            return _taskqueue.empty();
        }

    public:
        Thread_Pool(int num = 5) : _num(num)
        {
            pthread_mutex_init(&_mtx, NULL);
            pthread_cond_init(&_con, NULL);
        }

        static void *rountine(void *args)
        {
            pthread_detach(pthread_self());
            Thread_Pool*tp=(Thread_Pool*)args;
            while (1)
            {
                tp->lock();
                if(tp->empty())
                {
                    tp->wait(); 
                }
                T data;
                tp->Pop(&data);
                tp->unlock();

                data();
            }
        }

        void ThreadInit()
        {
            pthread_t tid;
            for (int i = 0; i < _num; ++i)
            {
                pthread_create(&tid,nullptr,rountine,(void*)this);
            }
        }

        void Push(const T &data)
        {
            lock();
            _taskqueue.push(data);
            unlock();
            wakeup();
        }

        void Pop(T*data)
        {
            *data=_taskqueue.front();
            _taskqueue.pop();
        }

        ~Thread_Pool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_con);
        }
    };
}